#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "context.h"

ctx * ctx_new()
{
	ctx * p = (ctx *)malloc(sizeof(struct ctx));
	memset(p, 0, sizeof(struct ctx));
	return p;
}

int ctx_free(ctx * p)
{
	if(p == NULL){
		return -1;
	}
	free(p->uni);
	p->uni = NULL;
	free(p->bi);
	p->bi = NULL;
	p->num = 0;
	return 0;
}

/*
char ctx_mapping(const ctx * p, unsigned int i)
{
	if(p == NULL || p->map == NULL || i >= p->num){
		return -1;
	}
	return p->map[i];
}

int ctx_get_uni(const ctx * p, unsigned int i)
{
	if(p == NULL || p->uni == NULL || i >= p->num){
		return -1;
	}
	return p->uni[i];
}

int ctx_get_bi(const ctx * p, unsigned int i, unsigned int j)
{
	if(p == NULL || p->bi == NULL || i >= p->num || j >= p->num){
		return -1;
	}
	return p->bi[i * p->num + j];
}
*/

#define NEW_BI(id0, id1, ctxp)		\
	((-log((double)ctx_get_bi(ctxp, id0, id1)+1) + log((double)ctx_get_uni(ctxp,id0)+1)) * 1000)

static int preprocess(ctx * p)
{
	if(p->total_freq == 0){
		return 1;
	}
	int * newbi = (int *)malloc(sizeof(int) * p->num * p->num);
	if(newbi == NULL){
		return -1;
	}
	int i, j;
	for(i = 0; i < p->num; i ++){
		for(j = 0; j < p->num; j ++){
			newbi[i * p->num + j] = NEW_BI(i, j, p);
		}
	}
	free(p->bi);
	p->bi = newbi;
	return 0;
}

static int parse_line(char * line, unsigned int num, const char * delim, 
				void * dst, unsigned int isize)
{
	int i;
	char * save;
	char * tok = strtok_r(line, delim, &save);
	for(i = 0; i < num; i ++){
		if(tok == NULL){
			return -1;
		}
		if(isize == 4){//int
			*(int *)(dst + i * 4) = atoi(tok);
		}else if(isize == 1){//char
			*(char *)(dst + i) = tok[0];
		}else{
			return -2;
		}
		tok = strtok_r(NULL, delim, &save); 
	}
	return 0;
}

int ctx_load(ctx * p, const char * ctx_path)
{
	if(ctx_path == NULL || p == NULL || p->bi != NULL || p->uni != NULL || p->num > 0){
		return -1;
	}
	FILE *fp = fopen(ctx_path, "r");
    if(fp == NULL){
        return -2;
    }
	char line[CTX_LINE_MAX] = {0};
	//num
	if(fgets(line, CTX_LINE_MAX, fp) == NULL){
		return -3;
	}
	if(sscanf(line, "%u\n", &p->num) != 1){
		return -4;
	}
	p->uni = (int *)malloc(sizeof(int) * p->num);
	if(p->uni == NULL){
		return -5;
	}
	p->bi = (int *)malloc(sizeof(int) * p->num * p->num);
	if(p->bi == NULL){
		return -6;
	}
	p->map = (char *)malloc(sizeof(char) * p->num);
	if(p->map == NULL){
		return -7;
	}
	//map
	if(fgets(line, CTX_LINE_MAX, fp) == NULL){
		return -8;
	}
	if(parse_line(line, p->num, "\t", p->map, 1) < 0){
		return -9;
	}
	//total_freq
	if(fgets(line, CTX_LINE_MAX, fp) == NULL){
		return -10;
	}
	if(sscanf(line, "%d\n", &p->total_freq) != 1){
		return -11;
	}
	//uni
	if(fgets(line, CTX_LINE_MAX, fp) == NULL){
		return -12;
	}
	if(parse_line(line, p->num, "\t", p->uni, 4) < 0){
		return -13;
	}
	//bi
	int i;
	for(i = 0; i < p->num; i ++){
		if(fgets(line, CTX_LINE_MAX, fp) == NULL){
			return -14;
		}
		if(parse_line(line, p->num, "\t", p->bi + i * p->num, 4) < 0){
			return -15;
		}
	}
	if(preprocess(p) < 0){
		return -16;
	}
	return 0;
}

#ifdef CONTEXT_MAIN
int main()
{
	ctx * p = ctx_new();
	if(p == NULL){
		return -1;
	}
	int ret = ctx_load(p, "/home/aaron/workspace/hiseg/clasdict/nr.ctx");
	if(ret < 0){
		fprintf(stderr, "ctx load err: %d\n", ret);
		return -2;
	}
	int i, j;
	for(i = 0; i < p->num; i ++){
		printf("%d\t", p->uni[i]);
	}
	printf("\n\n");
	for(i = 0; i < p->num; i ++){
		printf("%c\t", p->map[i]);
	}
	printf("\n\n");
	for(i = 0; i < p->num; i ++){
		for(j = 0; j < p->num; j ++){
			printf("%d\t", p->bi[i * p->num + j]);
		}
		printf("\n");
	}
	printf("\n");
	ctx_free(p);
	return 0;
}
#endif
